General Remarks
- Group work is NOT allowed in the lab. You have
to work alone. Discussions with colleagues (e.g., in the forum) are
allowed but the code has to be written alone.
- Be sure to check the Tricky Parts section for questions!
- Further reading is provided under tutorials
- In order to guarantee that all students can work fluently, do
not waste resources on the lab server (i.e., do not let your CORBA
servers run unnecessarily, kill your running zombie processes,...)
Submission Guide
Submission
- You must upload your solution using the Teaching Tool before the submission deadline: 18.01.2008, 18:00 cet. - the deadline is hard!
- You are responsible for submitting your solution in time!
Please make sure that your upload was successful (i.e., you should be
able to download your solution in the teaching tool - as the tutors
will do during the interview). If you do not submit, you won't get any
points!
- You have to upload your solution as a ZIP file. Please
submit only the sources of your solution (not the compiled class files
and no third-party libraries).
- Before the submission deadline, you can upload your solution
as often as you like. Remember that only your last submission is taken
into consideration!
- Your submission must compile and run in our lab environment. Please test before you submit.
- Please provide ant-tasks to ease testing. You may use our ant template.
Interviews
- After the submission deadline, there will be a mandatory
interview (Abgabegespräch). You must register for a time slot to the
interviews using the Teaching Tool.
- You can do the interview only if you have submitted your solution before the deadline!
- The interviews start two weeks before the main "interview" - week.
- The interview will take place in the DSLab. During the interview, you will be asked about the solution that you have uploaded (i.e., changes after the deadline will not be taken into account!). In the interview you need to explain your code, design and architecture in detail.
- Remember that you can do the interview only once!
Description
In this assignment you will learn:
- the basics of CORBA (Common Object Request Broker Architecture)
- how to write a CORBA solution by starting with an IDL (Interface Description Language)
- how to generate Java artifacts from CORBA
- how to implement simple CORBA objects and clients
- how to use transactions in CORBA
This year you shall use CORBA to implement a simple(!) and transaction-aware flight booking
system.
Overview
CORBA
Objects are hosted by server applications that provide one or more
object instances to clients. The communication of both the client and
the server is done with so called ORBs
(Object Request Brokers) that deal with marshaling (encoding arguments
in a platform independent-format) and unmarshaling (decoding
platform-independent data type representations into platform specific
formats) and invocation of CORBA operations. One primary advantage of
CORBA compared to other technologies such as RMI, .NET Remoting, or Web
services is its coverage of services. That is, CORBA supports the full
set of additional services that are required in most distributed system
environments such as naming and trading, transaction and
synchronization, notification and security services.
You will use the CORBA transaction service to let
multiple object servers work together in a distributed transaction. You
shall use this transaction service to realize an all or nothing policy:
either all requests succeed or none.
The primary idea of this assignment is to develop a
very simple flight reservation system (FRS). Several airlines want to
build a common system (the FRS), so that customers can centrally get
information about offered flights and make bookings. Since every
airline has its own information system, possibly implemented in
different languages on different platforms, a standard has to be used
for integrating the solutions - therefore CORBA is chosen.
Domain
Let's explore the domain of our simplified flight reservation system.
- Airlines have a name and a unique number.
- Flights are offered by airlines. Each flight has a unique number, a number of seats, a departure and a destination airport.
- Customers make bookings, we only need their first and last name.
- Single Flight Booking: This is a booking of
exactly one flight offered by one airline. The airlines have to store
the booking information (flight, customer and number of seats)
themselves, because they might use other reservation systems as well.
- Booking: A booking consists of one or
several single flight bookings and is made by exactly one customer.
This means that a customer may use our FRS to make a transparent
distributed booking among different airlines. Since the airlines store
the single flight booking information, and we don't want to have
redundant data, the FRS shall only store the common booking
information:
- A unique booking id for the whole booking,
- the customer's data and
- for each flight the booking id assigned by the offering airline as well as the airline's number.
Example
Here's an example to clarify the booking process:
Bob Willey wants to fly from London to Vienna
(British Airways "BA", Flight number: "BA 1234") and afterwards from
Vienna to Munich (Austrian Airlines "OS", Flight number: "OS 3222").
These flights are offered by different airlines, so when Bob decides to
book these flights, our FRS has to communicate with each participating
airline, to which it forwards the single flight bookings.
The FRS contacts the British Airways system, asks it for a booking for
flight "BA 1234" and receives the airline booking id 20. Next the FRS
asks Austrian Airlines for a booking for flight "OS 3222" and gets the
airline booking id 12. The booking is now complete and the FRS assigns
a unique booking id (101) for the whole transaction and stores the
necessary information:
- BookingId: 101
- Customer: "Bob Willey"
- Bookings: 20 - "BA", 12 - "OS"
Server Implementation details
Interfaces
To implement our flight reservation system we need the following two interfaces:
- FlightReservationSystem
- The customers interact with this interface, which acts as the
coordinator for bookings, so it is responsible for creating distributed
transactions, committing them in case of success and rolling them back
on failure.
- Required functionality:
Booking of several flights as a single transaction:
A customer hands in a number of single
flight bookings (they each may contain the airline number, the flight
number and the number of requested seats), our FRS is responsible for
forwarding the requests to the airline systems and executing the single
flight bookings within one transaction. The FRS shall return the
assigned booking id.
Updating a booking as a single transaction:
A customer may want to update his
booking. He/she may add new single flight bookings or cancel already
booked seats, for this he/she submits the booking id, a number of
single flight bookings (as above) and a number of cancelling requests
(each may contain the single flight booking id as well as the number of
cancelled seats). The FRS has to forward the requests to the
appropriate airline systems.
Cancelling a booking as a single transaction:
A customer may want to cancel the booking
as a whole, so he/she submits the id of the booking to cancel. The FRS
has to cancel each single flight booking at the airline systems.
Sending booking information:
It shall be possible to request booking
informations by transmitting a booking id. The answer has to include
all necessary informations (such as single flight booking ids, flight
numbers, number of booked seats and the airline numbers). Therefore the
FRS has to contact each airline system to gather the single flight
booking informations.
Sending flight information:
The FRS shall return informations about
all flights of all known airlines. This information contains flight
numbers, name and number of the offering airline, the number of seats
as well as the number of available seats and finally the departure and
destination airport. Do not store the flights in your FRS
implementation, request them each time from the airlines.
- Error handling
In case of invalid request parameters
(e.g. unexisting booking id, unknown airline number, ...) you have to
inform the client appropriately.
Please note that you only check the
parameters which are relevant for the FRS. E.g. if you receive a
booking request, don't request all flights from the specified airline
and check whether there's a flight with the number specified existing
and if it has enough available seats. It's the airline's job to do
that, since it might collaborate with other reservation systems. So
checking first all values and afterwards executing the transaction is
wrong, you first have to start the transaction and forward the requests
to the airline flight reservation systems. In case of an error you have
to rollback the transaction, otherwise you may commit it.
- AirlineFlightReservationSystem
- This interface is required to be implemented by all participating airlines in the FRS.
- As the booking operations
(book/cancel seats/cancel booking) have to be executed within
transactions, the interface has to extend the
CosTransaction::Resource and the CosTransaction::TransactionalObject interfaces. The CosTransaction::TransactionalObject
is just a markup interface and hence has no operations at all (primary
a historic relict from previous CORBA standards). However, you have to
implement the 5 operations of the Resource interface. You can skip implementing the forget operation and implement the commit_one_phase operation as in the JacORB sample. The prepare method shall return one of the three values Vote.VoteCommit, Vote.VoteRollback, Vote.VoteReadOnly depending if the changes shall be committed, or rolled back. Vote.VoteReadOnly shall be used if there were no changes at all. It is allowed that you stick totally on using exceptions and you simply return Vote.VoteCommit. However, this depends on your implementation decisions. The commit method makes any changes to the airline's bookings complete. The rollback method undoes these changes.
- Required functionality:
Booking of a single flight within a transaction:
This operation is called within an FRS
booking respectively update booking operation - the airline has store
the single flight booking information (customer, flight and number of
seats). It shall return the assigned single flight booking id. Make
sure that there are enough seats available and the flight exists.
Cancelling of booked seats within a transaction:
This operation is called within an FRS
update booking operation. If the number of cancelled seats is equal to
the number of booked seats, this single flight booking has to be
deleted (make sure to inform the FRS about that). You have to ensure
that the relevant booking exists (identified by a single flight booking
id) and that only as many seats are cancelled as booked.
Cancelling a booking within a transaction:
This operation is called within an FRS
cancel booking operation. Remove the booking identified by a single
flight booking id. Ensure that the booking exists.
Sending booking information:
This operation is called within an FRS
get booking information operation. It shall be possible to request
single flight booking informations by transmitting a single flight
booking id. The answer has to include all necessary informations (such
as single flight booking id, flight number and number of booked seats).
Sending flight information:
This operation is called within an FRS
get flights operation. It has to return the flight numbers, the number
of seats as well as the number of available seats and finally the
departure and destination airport.
Sending airline information:
Finally it shall be possible to request the airline's name and number. By this our FRS can identify the different airlines.
IDL file
Use the information provided to create your IDL
file. Of course, there are several possibilities how to design your
interfaces, nevertheless we require you to follow a few constraints:
- use at least one CORBA valuetype
- use one or several exceptions for indicating invalid requests (e.g. booking 20 seats if only 10 are available)
- every booking action in both interfaces (new booking, update booking, cancel booking) must be implemented using implicit and explicit transactions (e.g. bookImplicit and bookExplicit).
AirlineFlightReservationSystem startup
As
you may have noticed there are no remote methods for creating flights.
This shall be accomplished by reading in a properties file of the
following format on startup of the AirlineFlightReservationSystem server (sample):
#X = 1...3 Provide at least 3 flights per airline!
bindingName=AustrianAirlines | #name used for binding in CORBA Naming Service |
name=Austrian Airlines | #airline name |
number=OS 12 | #airline number |
flightX.number=OS 2933 | #flight number |
flightX.from=Vienna | #departure airport |
flightX.dest=Innsbruck | #destination airport |
flightX.seats=200 | #number of seats |
If you don't know how to load properties files from the file system take a look at our hint section.
FlightReservationSystem startup
Our FRS is informed about the available airlines also by reading in a properties file on startup (sample):
# Provide at least two airlines!
SkyEurope | #name used for binding by the airline services |
AustrianAirlines | |
It then has to look them up in the naming service and store their
references for executing the client requests.
You can expect that all airline service systems are up and registered
to the naming service when the FRS is started. The FRS also has to bind
itself to the naming service so that clients can look it up. You may
hardcode that name.
Naming and Transaction Service
Every student has to start its own naming and trading service. Please refer to Hints and the JacORB Programming Guide for information about starting them. So if you don't require the services anymore, stop them before you log out!
Test Client Details
For all your testing we expect the following prerequisite:
There must be at least two airlines registered at the FRS offering each at least 3 flights.
Implement a test client (using JUnit) that demonstrates the following things:
Valid booking.
- Make a booking consisting of three single flight bookings of two different airlines.
- You have to check that the number of available seats on each flight decreased by the number of booked seats.
Invalid booking.
- Make a booking consisting of three single flight bookings of
two different airlines. The third single flight booking has to request
more seats than are available on the flight.
- You have to check that you receive an exception or an
exceptional return value and that the number of available seats on each
flight did not change.
Valid update of a booking.
- First execute a successful booking consisting of three single
flight bookings of two different airlines. Then retrieve the booking
information, cancel some seats and add a new single flight booking.
- You have to check that the number of available seats on each flight is correct.
Invalid update of a booking.
- First execute a successful booking consisting of three single
flight bookings of two different airlines. Then retrieve the booking
information, cancel more seats than were booked and add a new flight
booking.
- You have to check that you receive an exception or an
exceptional return value and that the number of available seats on each
flight was only decreased by the number of booked seats of the first
booking.
Valid cancellation of a booking.
- First execute a successful booking consisting of three single
flight bookings of two different airlines. Then retrieve the booking
information and cancel the booking.
- You have to check that the number of available seats on each flight did not change.
Invalid cancellation of a booking.
- Cancel a non existing booking.
- You have to check that you receive an exception or an exceptional return value.
For each demonstration you have to provide test cases for explicit as well as implicit use of transactions (i.e. you have to provide at least 12 test cases).
Transactions Support
Implicit
- Using implicit transactions means that transaction contexts
storing the current state of a transaction are not directly visible in
client or server code but is automatically added by so-called
interceptors - in CORBA interceptors hook in requests and may modify
the transmitted data such as arguments or may add service contexts such
as in our case.
- To inform an ORB that it shall use the already predefined interceptor for implicit transactions the ORB
init method takes also a java.util.Properties argument that takes a property with value org.jacorb.transaction.TransactionInitializer. This is a class that registers an object of type org.omg.CosTransactions.Current as an initial reference named TransactionCurrent. This reference can then be retrieved with orb.resolve_initial_references. The key of the property may be arbitrary but must start with org.omg.PortableInterceptor.ORBInitializerClass. You may use the same property keys as in the JacORB demo.
- The
begin operation of the org.omg.CosTransactions.Current
interface may be used to initiate a transaction. The timeout shall be
set to a value of 40. This has to be set before you begin a
transaction. After a transaction has begun you can call whatever
transaction aware functionality of CORBA objects you want. The
transaction context is transmitted implicitly. For rolling back a
transaction you have to call the rollback function (surprisingly). Committing the transaction is done via the commit
operation (use true as argument). Never kill a server (regardless how)
that has started a transaction before the timeout has passed. When you
do manual tests you can set the timeout to a smaller value.
- From transaction aware objects you have to use the
org.omg.CosTransactions.Current interface, too. However, this time you shall receive the org.omg.CosTransactions.Control interface via the Current's get_control operation. Control supports two different functionalities: returning a Coordinator (with get_coordinator) and returning a Terminator (with get_terminator). In transaction aware operations you have to register the transaction aware CORBA object with the coordinator's register_resource
operation. The Resource's operations (prepare,rollback,commit) are then
used automatically when the transaction initiator calls commit or
rollback. In case of any TransactionServer related exception (example: Inactive) throw the runtime exception org.omg.CORBA.TRANSACTION_ROLLEDBACK. To get the exact syntax of the transaction server related operations take a look at the CosTransactions.idl or study the OMG Transaction Service Specification.
Explicit
- The main difference to implicit transactions is the way how
the transaction context is propagated to all transaction resources
respectively transactional objects. This time no CORBA interceptors do
the work for you, you have to transfer the necessary objects on your
own.
- To create transactions explicitly you may use the
org.omg.CosTransactions.TransactionFactory interface. You can get an instance by using the orb method resolve_initial_references with the right parameters (see the JacORB demo for details). Again use a timeout of 40.
- The TransactionFactory
create
operation returns a Control instance, which has to be propagated to all
object calls that should be part of the transaction. There the same
procedure as with implicit transactions can be applied.
- For executing a commit respectively a rollback you have to use the
org.omg.CosTransactions.Terminator interface. A reference can be obtained by calling get_terminator on the Control object.
IDL compiling
For compiling your IDL file, which uses transaction service interfaces, you have to
- write
#include <CosTransactions.idl> at the top of your IDL file to include the interface definitions
- and therefore tell the JacORB IDL compiler where to find the required IDL file
<CosTransactions.idl>: Use the -I option (e.g. -I/opt/jacorb/idl/omg/) to do this. If you use our ant template this option is already included (take a look at the idl-compile target).
Hints & Tricky Parts
- Study the JacORB programmer's guide, in particular chapter 4 - Getting Started - explains how to program a CORBA server and a CORBA client with JacORB.
Chapter 5 explains how to access the name service. Chapter 4 contains
everything you need to implement your server and client (except the
transactional stuff).
- In order to use JacORB
instead of the built-in (and incomplete) ORB of SUN that is provided
with Java, you have to provide two arguments to the VM with -D:
-Dorg.omg.CORBA.ORBClass=org.jacorb.orb.ORB and
-Dorg.omg.CORBA.ORBSingletonClass=org.jacorb.orb.ORBSingleton.
You also have to include all the
JacORB JAR files (located in the lib directory of the
JacORB installation) in the CLASSPATH . Instead of manually applying these settings, you can also use the
jaco shell script that is located in the
$JACORB_HOME/bin
directory. This script invokes Java with the appropriate VM arguments
and classpath settings. Note that you still have to provide the name of
the Java class you would like to start. Our
ant template already includes these settings.
- Properties for implicit transactions:
The server and clients MUST provide a property list during ORB initialization that contains following key-value pair Key:org.omg.PortableInterceptor.ORBInitializerClass.TSClientInit or org.omg.PortableInterceptor.ORBInitializerClass.TSServerInit with the value org.jacorb.transaction.TransactionInitializer. This setting is required for creating transactions implicitly. Without this setting you will only get exceptions!
- Value type factories:
- In your IDL file you have to use one
valuetype. Read chapter 9 of the JacORB Programming Guide to learn how to create valuetypes and valuetype factories.
- To register your factory with the ORB use the
orb.register_value_factory()
method on startup. As first parameter you have to submit the IDL
identification string, which you can obtain by calling the static YourValueTypeHelper.id() method. As the second argument you have to apply your ValueFactory implementation.
- JacORB services:
All described service commands are located in the
$JACORB_HOME/bin directory.
You need the naming service to bind and lookup your CORBA objects (this is quite similar to the rmiregistry from the last lab).
Usage: ns -Djacorb.naming.ior_filename=$HOME/NS_REF
For locating the naming service within your programs, you have to copy the
jacorb_properties.template from
$JACORB_HOME/etc to the directory where you execute your servers/clients and rename it to
jacorb.properties. Then edit the
ORBInitRef.NameService entry and set it to the appropriate path (e.g.
ORBInitRef.NameService=
file:///dslab/home/dslab/dslabXXX/NS_REF). There you can also edit a lot of configuration parameters when invoking
JacORB, although you don't have to. In our provided
ant template we included convenient defaults for the naming service properties, so you don't have to use the
jacorb.properties anymore.
You first have to start the naming service as described above.
Usage: ts -ORBInitRef NameService=file://$HOME/NS_REF
If you are working at home (it's a GUI
application, so you can't use it on pasta/pizza via ssh) you can use
this tool to view the objects bound to the naming service. This is
helpful if you are unsure about your binding code (the transaction
service is also visible there if it was started successfully).
Usage: nmg -ORBInitRef NameService=file://$HOME/NS_REF
We also provide convenient ant-targets within our
ant template to start these services.
- Using JacORB at home:
- Download the JacORB src distribution.
- Build the libraries and shell scripts via
ant. Note that building with Java 6 fails, use Java 5 instead.
- Set the environment entry
$JACORB_HOME.
- Include
$JACORB_HOME/bin into your $PATH variable.
- Reading in a .properties file:
- A properties file can be easily read by using the
java.util.Properties class. Use the load method with a FileInputStream that is connected to your file.
- Afterwards you can access the properties with
getProperty.
Ant Template
For Lab 3 you can extend this build.xml.
- We provide convenient ant targets for starting the JacORB services as well as the idl compilation process. We also included the necessary system properties for JacORB to work and to use the naming service. Also try to start the services without the ant targets to learn how to use them.
- This one supports JUnit. The task definition entry in this file is appropriate for the combination of ant-1.6.x and JUnit as installed on the lab servers pasta and pizza.
In addition you will need to include the static method suite() in your JUnit test classes:
import org.junit.*;
public class TestClassX {
... test methods
public static junit.framework.Test suite() {
return new junit.framework.JUnit4TestAdapter(TestClassX.class);
}
}
(If you use ant-1.7 (at your home PCs) you do not need to include this method. However, if you want to start the tests in the lab you should include it).
Proposed Tutorials
This is the original OMG CORBA Specification. You can use it as a reference if you are specially interested in CORBA.
This is the original OMG Transaction
Service Specification. In general, it is not necessary to read all of
this. However, in Section 2 all involved CORBA interfaces are explained
(as Resource, Control, Coordinator, Terminator).
Describes the mapping from IDL to Java.
- Study the JacORB Programming Guide. Specifically chapters 4, 5 and 9 are interesting for this lab. You can find it in the JacORB distribution in
doc/ProgrammingGuide.pdf.
- The JacORB bank demo shows how
to work with implicit and explicit transactions and is a good reference
for this lab. You can find it in the JacORB distribution in
demo/bank/transaction.
- Java CORBA Introduction
This is a nice introduction for using CORBA with Java. Note that it's not JacORB specific!
Here you can find several informations about CORBA with Java, again this is not related to using JacORB.
Proposed Literature
Advanced CORBA(R) Programming with C++ by by Michi Henning and Steve Vinoski